#include "libMediaPushWorker.h"


libMediaPushWorker::libMediaPushWorker()
{
	m_bExit = false;
	m_bInitOK = false;
	m_hRtmpHandle = NULL;
	m_pThreadPush = NULL;

	m_ppslen = 0;
	m_spslen = 0;
}


libMediaPushWorker::~libMediaPushWorker()
{

}

void libMediaPushWorker::MediaCapData_CB(int nType, char* pBuff, int nBuffLen, bool bKeyFrame)
{
	if ( !m_bInitOK || m_bExit )
	{
		return;
	}
	int nRealLen = nBuffLen;
	MediaFrame* pFrame = new MediaFrame;
    int8_t* pCurBuff = new int8_t[nBuffLen+256];

	// -----------------------------
	if ( nType == SRS_RTMP_TYPE_VIDEO)
	{
		// Video
		static unsigned char btHeader[4];
		btHeader[0] = 0x00;
		btHeader[1] = 0x00;
		btHeader[2] = 0x00;
		btHeader[3] = 0x01;

		if (bKeyFrame)
		{
			nRealLen = nBuffLen + 8 + m_spslen + m_ppslen;
			memcpy(pCurBuff, btHeader, 4);
			memcpy(pCurBuff + 4, m_sps, m_spslen);
			memcpy(pCurBuff + 4 + m_spslen, btHeader, 4);
			memcpy(pCurBuff + 4 + m_spslen + 4, m_pps, m_ppslen);
			memcpy(pCurBuff + 4 + m_spslen + 4 + m_ppslen, btHeader, 4);
			memcpy(pCurBuff + 4 + m_spslen + 4 + m_ppslen + 4, pBuff + 4, nBuffLen - 4);
		}
		else
		{
			nRealLen = nBuffLen;
			memcpy(pCurBuff, btHeader, 4);
			memcpy(pCurBuff + 4, pBuff + 4, nBuffLen - 4);
		}
	}
	else {
		// Audio or script
		nRealLen = nBuffLen;
		memcpy(pCurBuff, pBuff, nBuffLen);
	}
	// --------------------------

	long tmClock = clock();
	pFrame->pBuff = (int8_t*)pCurBuff;
	pFrame->nLen = nRealLen;
	pFrame->timestramp = tmClock;
	pFrame->bKey = bKeyFrame;
    pFrame->nType = nType;

	m_lockMedia.lock();
	//TRACE(L"Push MediaList Size: %d\n", m_ListMediaData.size());
	m_ListMediaData.push_back(pFrame);
	m_lockMedia.unlock();
}

void libMediaPushWorker::Set_SPSAndPPS(unsigned char*sps, long&spslen, unsigned char*pps, long&ppslen)
{
	memset(m_sps, 0, 100);
	memcpy(m_sps, sps, spslen);
	m_spslen = spslen;

	memset(m_pps, 0, 100);
	memcpy(m_pps, pps, ppslen);
	m_ppslen = ppslen;
}

void libMediaPushWorker::RunPushTH()
{
	MediaFrame* pCurFrame;
    
	while (!m_bExit)
	{
		Sleep(1);
		if (!m_bInitOK)
		{
			continue;
		}
		m_lockMedia.lock();
		if ( m_ListMediaData.empty() )
		{
			m_lockMedia.unlock();
			continue;
		}
		pCurFrame = m_ListMediaData.front();
		m_ListMediaData.pop_front();
		m_lockMedia.unlock();

		// push
		if ( m_hRtmpHandle)
		{
            pCurFrame->timestramp = clock();
            if (pCurFrame->nType == SRS_RTMP_TYPE_VIDEO)
            {
                srs_h264_write_raw_frames(m_hRtmpHandle, (char*)pCurFrame->pBuff, pCurFrame->nLen, pCurFrame->timestramp, pCurFrame->timestramp);
            }
            else if (pCurFrame->nType == SRS_RTMP_TYPE_AUDIO)
            {
                srs_audio_write_raw_frame(m_hRtmpHandle, 10/*AAC*/, 3/*44K*/, 1/*16*/, 1/*Mono*/, (char*)pCurFrame->pBuff, pCurFrame->nLen, pCurFrame->timestramp);
            }
            else {
                srs_rtmp_write_packet(m_hRtmpHandle, pCurFrame->nType, pCurFrame->timestramp, (char*)pCurFrame->pBuff, pCurFrame->nLen);
                pCurFrame->pBuff = NULL;
            }
		}
        if(pCurFrame->pBuff)
    		delete[] pCurFrame->pBuff;
		delete pCurFrame;
	}
}

void libMediaPushWorker::Init(std::string strUrl)
{
	if (m_hRtmpHandle)
	{
		return;
	}
	
    m_hRtmpHandle = srs_rtmp_create(strUrl.c_str());
    if ( !m_hRtmpHandle )
    {
        return;
    }
    if (srs_rtmp_handshake(m_hRtmpHandle) != 0) {
        srs_human_trace("shake hand failed.");
        return;
    }
    if (srs_rtmp_connect_app(m_hRtmpHandle) != 0) {
        srs_human_trace("connect vhost/app failed.");
        return;
    }
    //srs_rtmp_set_schema(m_hRtmpHandle, srs_url_schema_normal);
    srs_rtmp_publish_stream(m_hRtmpHandle);

    if (!m_pThreadPush) {
        m_pThreadPush = new std::thread(&libMediaPushWorker::RunPushTH, this);
        m_pThreadPush->detach();
    }

    m_bInitOK = true;
}

void libMediaPushWorker::Release()
{
	m_bInitOK = false;
	m_bExit = true;
	if (!m_hRtmpHandle)
	{
		return;
	}
    srs_rtmp_destroy(m_hRtmpHandle);
    m_hRtmpHandle = NULL;
	m_pThreadPush = NULL;
}
